home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.13 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  11.1 KB  |  384 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 4.13: Pathfinding                                //
  3. // Written by: C. Granberg, 2005                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include "debug.h"
  9. #include "heightMap.h"
  10. #include "terrain.h"
  11.  
  12. #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
  13. #define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
  14.  
  15. struct VERTEX{
  16.     VERTEX();
  17.     VERTEX(D3DXVECTOR3 pos, D3DCOLOR col){position = pos; color = col;}
  18.     D3DXVECTOR3 position;
  19.     D3DCOLOR color;
  20.     static const DWORD FVF;
  21. };
  22.  
  23. const DWORD VERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  24.  
  25. class APPLICATION
  26. {
  27.     public:
  28.         APPLICATION();
  29.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  30.         HRESULT Update(float deltaTime);
  31.         HRESULT Render();
  32.         HRESULT Cleanup();
  33.         HRESULT Quit();
  34.         DWORD FtoDword(float f){return *((DWORD*)&f);}
  35.  
  36.     private:
  37.         IDirect3DDevice9* m_pDevice; 
  38.         TERRAIN m_terrain;
  39.  
  40.         int m_numPoints;
  41.         float m_angle, m_radius;
  42.         bool m_wireframe, m_walkGrid;
  43.         INTPOINT m_start, m_goal;
  44.         HWND m_mainWindow;
  45.         ID3DXFont *m_pFont;
  46.  
  47.         //Vertex buffer for points
  48.         std::vector<VERTEX> m_path;
  49.         IDirect3DVertexBuffer9 *m_pVb;
  50. };
  51.  
  52. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  53. {
  54.     APPLICATION app;
  55.  
  56.     if(FAILED(app.Init(hInstance, 800, 600, true)))
  57.         return 0;
  58.  
  59.     MSG msg;
  60.     memset(&msg, 0, sizeof(MSG));
  61.     int startTime = timeGetTime(); 
  62.  
  63.     while(msg.message != WM_QUIT)
  64.     {
  65.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  66.         {
  67.             ::TranslateMessage(&msg);
  68.             ::DispatchMessage(&msg);
  69.         }
  70.         else
  71.         {    
  72.             int t = timeGetTime();
  73.             float deltaTime = (t - startTime)*0.001f;
  74.  
  75.             app.Update(deltaTime);
  76.             app.Render();
  77.  
  78.             startTime = t;
  79.         }
  80.     }
  81.  
  82.     app.Cleanup();
  83.  
  84.     return msg.wParam;
  85. }
  86.  
  87. APPLICATION::APPLICATION()
  88. {
  89.     m_pDevice = NULL; 
  90.     m_mainWindow = 0;
  91.     m_angle = m_radius = 0.0f;
  92.     m_wireframe = false;
  93.     m_walkGrid = true;
  94.     m_pVb = NULL;
  95.     srand(GetTickCount());
  96. }
  97.  
  98. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  99. {
  100.     debug.Print("Application initiated");
  101.  
  102.     //Create Window Class
  103.     WNDCLASS wc;
  104.     memset(&wc, 0, sizeof(WNDCLASS));
  105.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  106.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  107.     wc.hInstance     = hInstance;
  108.     wc.lpszClassName = "D3DWND";
  109.  
  110.     //Register Class and Create new Window
  111.     RegisterClass(&wc);
  112.     m_mainWindow = CreateWindow("D3DWND", "Example 4.13: Pathfinding", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  113.     SetCursor(NULL);
  114.     ShowWindow(m_mainWindow, SW_SHOW);
  115.     UpdateWindow(m_mainWindow);
  116.  
  117.     //Create IDirect3D9 Interface
  118.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  119.  
  120.     if(d3d9 == NULL)
  121.     {
  122.         debug.Print("Direct3DCreate9() - FAILED");
  123.         return E_FAIL;
  124.     }
  125.  
  126.     //Check that the Device supports what we need from it
  127.     D3DCAPS9 caps;
  128.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  129.  
  130.     //Hardware Vertex Processing or not?
  131.     int vp = 0;
  132.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  133.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  134.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  135.  
  136.     //Check vertex & pixelshader versions
  137.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  138.     {
  139.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  140.     }
  141.  
  142.     //Set D3DPRESENT_PARAMETERS
  143.     D3DPRESENT_PARAMETERS d3dpp;
  144.     d3dpp.BackBufferWidth            = width;
  145.     d3dpp.BackBufferHeight           = height;
  146.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  147.     d3dpp.BackBufferCount            = 1;
  148.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  149.     d3dpp.MultiSampleQuality         = 0;
  150.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  151.     d3dpp.hDeviceWindow              = m_mainWindow;
  152.     d3dpp.Windowed                   = windowed;
  153.     d3dpp.EnableAutoDepthStencil     = true; 
  154.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  155.     d3dpp.Flags                      = 0;
  156.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  157.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  158.  
  159.     //Create the IDirect3DDevice9
  160.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  161.                                  vp, &d3dpp, &m_pDevice)))
  162.     {
  163.         debug.Print("Failed to create IDirect3DDevice9");
  164.         return E_FAIL;
  165.     }
  166.  
  167.     //Release IDirect3D9 interface
  168.     d3d9->Release();
  169.  
  170.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  171.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  172.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  173.  
  174.     LoadObjectResources(m_pDevice);
  175.     m_terrain.Init(m_pDevice, INTPOINT(100,100));
  176.     m_radius = 100.0f;
  177.  
  178.     //Set sampler state
  179.     m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  180.     m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  181.     m_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  182.  
  183.     return S_OK;
  184. }
  185.  
  186. HRESULT APPLICATION::Update(float deltaTime)
  187. {
  188.     //Control camera
  189.     m_angle += deltaTime * 0.5f;
  190.     D3DXMATRIX  matWorld, matView, matProj;        
  191.     D3DXVECTOR2 centre = D3DXVECTOR2(50.0f, 50.0f);
  192.     D3DXVECTOR3 Eye    = D3DXVECTOR3(centre.x + cos(m_angle) * m_radius, m_radius, -centre.y + sin(m_angle) * m_radius);
  193.     D3DXVECTOR3 Lookat = D3DXVECTOR3(centre.x, 0.0f,  -centre.y);
  194.  
  195.     D3DXMatrixIdentity(&matWorld);
  196.     D3DXMatrixLookAtLH(&matView, &Eye, &Lookat, &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
  197.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.3333f, 1.0f, 1000.0f );
  198.  
  199.     m_pDevice->SetTransform( D3DTS_WORLD,      &matWorld );
  200.     m_pDevice->SetTransform( D3DTS_VIEW,       &matView );
  201.     m_pDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  202.     
  203.     if(KEYDOWN('W'))
  204.     {
  205.         m_wireframe = !m_wireframe;
  206.         Sleep(300);
  207.     }
  208.     if(KEYDOWN('G'))
  209.     {
  210.         m_walkGrid = !m_walkGrid;
  211.         Sleep(300);
  212.     }
  213.     if(KEYDOWN('N'))
  214.     {
  215.         //Create new particles
  216.         do
  217.         {
  218.             m_start = INTPOINT(rand()%m_terrain.m_size.x, rand()%m_terrain.m_size.y);
  219.             m_goal = INTPOINT(rand()%m_terrain.m_size.x, rand()%m_terrain.m_size.y);
  220.             while(!m_terrain.GetTile(m_start)->m_walkable){m_start = INTPOINT(rand()%m_terrain.m_size.x, rand()%m_terrain.m_size.y);}
  221.             while(!m_terrain.GetTile(m_goal)->m_walkable || m_start == m_goal){m_goal = INTPOINT(rand()%m_terrain.m_size.x, rand()%m_terrain.m_size.y);}
  222.         }
  223.         while(m_terrain.GetTile(m_start)->m_set != m_terrain.GetTile(m_goal)->m_set);
  224.  
  225.         std::vector<INTPOINT> p = m_terrain.GetPath(m_start, m_goal);
  226.         m_path.clear();
  227.  
  228.         if(!p.empty())
  229.         {
  230.             for(int i=0;i<p.size();i++)
  231.             {
  232.                 float prc = i / (float)p.size();
  233.                 int red =  255 * prc;
  234.                 int green = 255 * (1.0f - prc);
  235.                 MAPTILE *t = m_terrain.GetTile(p[i]);
  236.                 m_path.push_back(VERTEX(D3DXVECTOR3(p[i].x, t->m_height + 0.1f, -p[i].y), D3DCOLOR_ARGB(255, red, green, 0)));
  237.             }
  238.         }
  239.  
  240.         std::vector<VERTEX> particles;
  241.         particles.push_back(VERTEX(D3DXVECTOR3(m_start.x, m_terrain.GetTile(m_start)->m_height + 0.5f, -m_start.y), D3DCOLOR_ARGB(255, 0, 255, 0)));
  242.         particles.push_back(VERTEX(D3DXVECTOR3(m_goal.x, m_terrain.GetTile(m_goal)->m_height + 0.5f, -m_goal.y), D3DCOLOR_ARGB(255, 255, 0, 0)));
  243.  
  244.         for(int y=0;y<m_terrain.m_size.y;y++)
  245.             for(int x=0;x<m_terrain.m_size.x;x++)
  246.                 if(m_terrain.GetTile(x, y)->g < 1000)
  247.                     particles.push_back(VERTEX(D3DXVECTOR3(x, m_terrain.GetTile(x, y)->m_height + 0.1f, -y), D3DCOLOR_ARGB(255, 0, 0, 255)));
  248.     
  249.         // Initialize particles
  250.         if(m_pVb != NULL)
  251.         {
  252.             m_pVb->Release();
  253.             m_pVb = NULL;
  254.         }
  255.  
  256.         if(FAILED(m_pDevice->CreateVertexBuffer(particles.size() * sizeof(VERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, VERTEX::FVF, D3DPOOL_DEFAULT, &m_pVb, 0)))
  257.             debug.Print("Failed to create particle vertex buffer");
  258.         else
  259.         {
  260.             VERTEX *v = NULL;
  261.             m_pVb->Lock(0, 0, (void**)&v, D3DLOCK_DISCARD);            
  262.             for(int i=0;i<particles.size();i++)
  263.                 v[i] = particles[i];
  264.             m_pVb->Unlock();
  265.  
  266.             m_numPoints = particles.size();
  267.         }        
  268.     }
  269.     else if(KEYDOWN(VK_ADD) && m_radius < 200.0f)
  270.     {
  271.         m_radius += deltaTime * 30.0f;
  272.     }
  273.     else if(KEYDOWN(VK_SUBTRACT) && m_radius > 5.0f)
  274.     {
  275.         m_radius -= deltaTime * 30.0f;
  276.     }
  277.     else if(KEYDOWN(VK_SPACE))
  278.     {
  279.         m_path.clear();
  280.  
  281.         if(m_pVb != NULL)
  282.         {
  283.             m_pVb->Release();
  284.             m_pVb = NULL;
  285.         }
  286.         
  287.         m_terrain.GenerateRandomTerrain(3);
  288.     }
  289.     else if(KEYDOWN(VK_ESCAPE))
  290.         Quit();
  291.  
  292.     return S_OK;
  293. }    
  294.  
  295. HRESULT APPLICATION::Render()
  296. {
  297.     // Clear the viewport
  298.     m_pDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0L );
  299.  
  300.     // Begin the scene 
  301.     if(SUCCEEDED(m_pDevice->BeginScene()))
  302.     {
  303.         if(m_wireframe)m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);    
  304.         else m_pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  305.  
  306.         m_terrain.Render();
  307.  
  308.         if(m_pVb != NULL)
  309.         {
  310.             D3DXMATRIX world;
  311.             D3DXMatrixIdentity(&world);
  312.             m_pDevice->SetTransform(D3DTS_WORLD, &world);
  313.  
  314.             m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  315.             m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
  316.             m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);
  317.  
  318.             m_pDevice->SetRenderState(D3DRS_POINTSIZE, FtoDword(0.3f));
  319.             m_pDevice->SetRenderState(D3DRS_POINTSIZE_MIN, FtoDword(0.0f));
  320.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_A, 0);
  321.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDword(0.0f));
  322.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDword(1.0f));
  323.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  324.  
  325.             m_pDevice->SetTexture(0, NULL);
  326.             m_pDevice->SetFVF(VERTEX::FVF);
  327.             m_pDevice->SetStreamSource(0, m_pVb, 0, sizeof(VERTEX));
  328.             m_pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, m_numPoints);
  329.  
  330.             m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
  331.             m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false);
  332.         }
  333.  
  334.         if(!m_path.empty())
  335.         {
  336.             m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  337.             m_pDevice->SetFVF(VERTEX::FVF);
  338.             m_pDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, m_path.size() - 1, &m_path[0], sizeof(VERTEX));
  339.         }
  340.         
  341.         RECT r[] = {{10, 10, 0, 0}, {10, 30, 0, 0}, {10, 50, 0, 0}, {10, 70, 0, 0}, {10, 110, 0, 0}};
  342.         m_pFont->DrawText(NULL, "W: Toggle Wireframe", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  343.         m_pFont->DrawText(NULL, "+/-: Zoom In/Out", -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  344.         m_pFont->DrawText(NULL, "N: New Path", -1, &r[2], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  345.         m_pFont->DrawText(NULL, "SPACE: Randomize Map", -1, &r[3], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  346.  
  347.         if(m_path.empty())
  348.             m_pFont->DrawText(NULL, "No Path found!", -1, &r[4], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  349.  
  350.         // End the scene.
  351.         m_pDevice->EndScene();
  352.         m_pDevice->Present(0, 0, 0, 0);
  353.     }
  354.  
  355.     return S_OK;
  356. }
  357.  
  358. HRESULT APPLICATION::Cleanup()
  359. {
  360.     try
  361.     {
  362.         m_terrain.Release();
  363.         UnloadObjectResources();
  364.  
  365.         m_pFont->Release();
  366.  
  367.         if(m_pVb != NULL)
  368.             m_pVb->Release();
  369.  
  370.         m_pDevice->Release();
  371.  
  372.         debug.Print("Application terminated");
  373.     }
  374.     catch(...){}
  375.  
  376.     return S_OK;
  377. }
  378.  
  379. HRESULT APPLICATION::Quit()
  380. {
  381.     ::DestroyWindow(m_mainWindow);
  382.     ::PostQuitMessage(0);
  383.     return S_OK;
  384. }